Rust から C のデータにアクセスする
C も Rust も関連データを 1 つのデータ構造にまとめるのに 構造体 を用いる この不整合を防ぐために、「FFI で用いる Rust の型には #[repr(C)] を付ける」
e.g.
code:lib.h
/// この構造体の変更は、lib.rs にも反映する必要がある
typedef struct {
uint8_t byte;
uint32_t integer;
} FfiStruct;
code:lib.rs
/// この構造体の変更は、lib.h / lib.c にも反映する必要がある
pub struct FfiStruct {
pub byte: u8,
pub integer: u32,
}
関数の場合と同様、一致していなくてもビルドツールは警告を出さないので、cargo-bindgen を用いて整合していることを CI でチェックすべきである warning.icon
Rust と C のデフォルトの文字列の定義が全く異なるため、扱う際には注意が必要
デフォルトの定義
Rust(String): UTF-8 でエンコードされたデータを保持する データには ゼロバイト(\0)を含むことがあるが、その長さを明示的に管理する したがって、"Hello\0World" という文字列の長さは 11 Byte となる C(char *): バイト値(符号ありかは不明)を保持する
長さは、データ内で最初に現れるゼロバイトによって暗黙的に決まる
したがって、"Hello\0World" という文字列の長さは 5 Byte となる
この差を埋めるために、
「 C の文字列をバインディングした(所有 された)文字列は CString 型として扱おう」 また、上記に対応する「借用 された文字列値は Cstr 型として扱おう」 Cstr::as_ptr を用いると、C の文字列(const char*)を受け取る FFI 関数に、データを渡すことができる const なので、渡された文字列の内容(char*)を変更する必要がある場合には使えない